package company.primary;

import javax.servlet.ServletOutputStream
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

import org.iweb.*
import org.iweb.html.api.AbstractHtmlElement
import org.iweb.html.api.Listener
import org.iweb.html.engine.render.IRenderEngine
import org.iweb.html.impl.basic.Form
import org.iweb.html.impl.basic.Script
import org.iweb.html.impl.basic.Form.CustomFormBean
import org.iweb.html.impl.js.state.ElementState
import org.iweb.html.impl.js.state.HtmlState
import org.iweb.html.impl.session.AppSession
import org.iweb.ioc.Bean
import org.iweb.ioc.Inject
import org.iweb.ioc.ServiceLookup
import org.iweb.ui.company.Company
import org.iweb.ui.layout.Layout
import org.iweb.ui.layout.LayoutFactory
import org.iweb.ui.page.Page
import org.iweb.ui.page.PageFactory
import org.iweb.util.BeanUtil
import org.iweb.web.json.JsonUtil;
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import com.thoughtworks.xstream.XStream
import com.thoughtworks.xstream.io.HierarchicalStreamWriter
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver
import com.thoughtworks.xstream.io.json.JsonWriter

@Company(hostname="localhost(:[0-9]*)",beanName="company.primary.DefaultCompany")
@Bean("company.primary.DefaultCompany")
class DefaultCompany {

	private static Logger log=LoggerFactory.getLogger(DefaultCompany.class);
	
	private String companyName;	
	private static Map<String, Class> groovyClass=new HashMap<String,Class>();
	
	private IRenderEngine renderEngine;
	private IRenderEngine renderEngine2;
	
	public void route(HttpServletRequest request,HttpServletResponse response,AppSession appSession){
		String path=request.getRequestURI().replaceFirst(request.getContextPath(), "");
		
		if(path!=null && !path.startsWith("/"))
			path="/"+path;
		
		if(path.startsWith("/actions")){
			handleActions(request,response,appSession);
			return;
		}
		
		Class c=PageFactory.getInstance().getPage(path);
		
		log.debug("From page factory -> path: "+path+" class: "+c);
		
		ServletOutputStream out=null;
		//String method=request.getParameter("method")!=null?request.getParameter("method"):"renderInt";
		
		if(c!=null){
			try {
				out=response.getOutputStream();
				Page ann=(Page) c.getAnnotation(Page.class);
				Object obj=renderObj(ann.renderMethod(), ServiceLookup.instance.get(ann.beanName()), appSession);
				if(obj!=null){
					
					if("true".equalsIgnoreCase(request.getParameter("nolayout"))){
						//At the first ajax call it doesn't need layout
						out.write(obj.toString().getBytes());
						return;
					}
					
					Class layout=LayoutFactory.getInstance().getLayout(ann.layout());
					
					Layout annL=(Layout) layout.getAnnotation(Layout.class);
					
					//obj=renderGroovyLayout(annL.renderMethod(),layout,appSession,request.getContextPath(),path);
					//obj=renderClass(annL.renderMethod(),layout,appSession,request.getContextPath(),path);
					obj=renderObj(annL.renderMethod(),ServiceLookup.instance.get(annL.beanName()),appSession,request.getContextPath(),path);
					
					out.write(obj.toString().getBytes());
				}
			} catch (Exception e) {
				e.printStackTrace();
				if(out!=null)
					try {
						out.write(e.getMessage().getBytes());
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				e.printStackTrace();
			}
			return;
		}
	}
	
	private void handleActions(HttpServletRequest request,
		HttpServletResponse response, AppSession appSession) {
		String listenerid = request.getParameter("listenerid");
		String beanid = request.getParameter("beanid");
		
		log.info(String.format("BeanId %s ListenerId %s",beanid,listenerid));
		
		Form.CustomFormBean bean = null;
		try {
			if (beanid != null && beanid.trim().length() > 0) {
				bean = new Form.BeanFactory().getBean(
						request.getParameterMap(),
						(CustomFormBean) this.getClass().getClassLoader()
								.loadClass(beanid).newInstance());
			}
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		
		if(listenerid!=null && appSession.getObserver().getListener(listenerid)!=null){
			Listener l=appSession.getObserver().getListener(listenerid);
			l.run(request, bean);
		}
		
		response.setContentType("application/json");
		
		try {
			response.getOutputStream().print(JsonUtil.toJSON(appSession.getAppState().getHtmlState().getElstates()));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

		/*
		public Object renderGroovyScript(String method,String scriptName, AppSession appSession){
			try {
				Class scriptClass=groovyClass.get(scriptName);
				
				if(scriptClass==null){
				
					try{
						scriptClass = IWebGroovyEngine.getGroovyScriptEngine().loadScriptByName(scriptName);
					}catch(ResourceException re){
						
					}
					
					if(scriptClass==null){
						try{
							scriptClass = IWebGroovyEngine.getGroovyScriptEngine().loadScriptByName(scriptName.replaceFirst(getCompanyName()+"/", ""));
						}catch(ResourceException re){
							//provo a cercare una cartella con questo nome
							scriptClass = IWebGroovyEngine.getGroovyScriptEngine().loadScriptByName(scriptName.replaceFirst(getCompanyName()+"/", "").replaceFirst(".groovy", "/Init.groovy"));
						}
					}
					
					groovyClass.put(scriptName, scriptClass);
				
				}
				
				return renderGroovyClass(method, scriptClass, appSession);
				
			} catch (Exception e) {
				e.printStackTrace();
				return e.getClass().getName()+" -> "+e.getMessage();
			}
		}
		*/
		
		public Object renderClass(String method,Class clazz, AppSession appSession,Object... parameters) throws Exception{
	
			// ?? nn ricordo il perchè
			//appSession.getGroovyScript().put(scriptName, scriptInstance);
			
			//Object result = null;
	
			//result = scriptClass.getMethod(method,null).invoke(scriptClass.newInstance(), null);
			Object result = BeanUtil.invokeByClass(clazz, method,parameters);
	
			if(result instanceof AbstractHtmlElement){
				
				if(appSession.getAppState().getScriptElement()!=null && appSession.getAppState().getScriptElement().size()>0)
					((AbstractHtmlElement)result).append(new Script(appSession.getAppState().getScriptElement()));
				
				return getRenderEngine().render((AbstractHtmlElement)result);
				//return ((AbstractHtmlElement)result).render();
			}
			
			return result;
			
		}
		
		public Object renderObj(String method,Object obj, AppSession appSession,Object... parameters) throws Exception{
			
			// ?? nn ricordo il perchè
			//appSession.getGroovyScript().put(scriptName, scriptInstance);
			
			//Object result = null;
	
			//result = scriptClass.getMethod(method,null).invoke(scriptClass.newInstance(), null);
			Object result = BeanUtil.invokeByObj(obj, method,parameters);
	
			if(result instanceof AbstractHtmlElement){
				
				if(appSession.getAppState().getScriptElement()!=null && appSession.getAppState().getScriptElement().size()>0)
					((AbstractHtmlElement)result).append(new Script(appSession.getAppState().getScriptElement()));
				
				return getRenderEngine().render((AbstractHtmlElement)result);
				//return ((AbstractHtmlElement)result).render();
			}
			
			return result;
			
		}
	
		
		
		
		public IRenderEngine getRenderEngine(){
			return renderEngine;
		}
		
		@Inject(id="IRenderEngine")
		public void setRenderEngine(IRenderEngine renderEngine){
			this.renderEngine=renderEngine;
		}
		
}
